"""
多数据库管理器

负责管理多个数据库实例，提供数据库级操作和路由功能
"""

import os
import sys
import json
import shutil
from typing import Dict, List, Optional, Any, Union
from datetime import datetime

# 添加当前目录到Python路径
current_dir = os.path.dirname(os.path.abspath(__file__))
if current_dir not in sys.path:
    sys.path.insert(0, current_dir)

from database_instance import DatabaseInstance, DatabaseInfo
from storage_engine import CachePolicy
from table_schema import Column, ColumnType
from statistics import Logger


class DatabaseManager:
    """多数据库管理器"""
    
    def __init__(self, data_root: str = "./data", 
                 default_cache_size: int = 100,
                 default_cache_policy: CachePolicy = CachePolicy.LRU,
                 enable_locking: bool = True):
        """
        初始化数据库管理器
        
        Args:
            data_root: 数据根目录
            default_cache_size: 默认缓存大小
            default_cache_policy: 默认缓存策略
            enable_locking: 是否启用锁机制
        """
        self.data_root = data_root
        self.default_cache_size = default_cache_size
        self.default_cache_policy = default_cache_policy
        self.enable_locking = enable_locking
        self.logger = Logger()
        
        # 确保数据根目录存在
        os.makedirs(data_root, exist_ok=True)
        
        # 数据库实例管理
        self.databases: Dict[str, DatabaseInstance] = {}
        
        # 系统元数据文件
        self.system_meta_file = os.path.join(data_root, "system.meta")
        
        # 加载系统元数据
        self._load_system_metadata()
        
        self.logger.info("DB_MANAGER", 0, f"Database manager initialized with data root: {data_root}")
    
    def _load_system_metadata(self):
        """加载系统元数据"""
        try:
            # 首先自动发现数据库目录中的数据库
            self._discover_existing_databases()
            
            if os.path.exists(self.system_meta_file):
                with open(self.system_meta_file, 'r', encoding='utf-8') as f:
                    metadata = json.load(f)
                
                # 加载已存在的数据库
                if 'databases' in metadata:
                    for db_name, db_info_dict in metadata['databases'].items():
                        try:
                            # 检查数据库目录是否存在
                            db_path = db_info_dict['path']
                            if os.path.exists(db_path):
                                # 延迟加载数据库实例
                                db_info = DatabaseInfo.from_dict(db_info_dict)
                                self.logger.info("LOAD_META", 0, f"Found database: {db_name}")
                            else:
                                self.logger.warn("LOAD_META", 0, f"Database path not found: {db_path}")
                        except Exception as e:
                            self.logger.error("LOAD_META", 0, f"Failed to load database {db_name}: {e}")
                
                self.logger.info("LOAD_META", 0, f"Loaded system metadata")
            else:
                # 新安装，创建初始元数据
                self._save_system_metadata()
                
        except Exception as e:
            self.logger.error("LOAD_META", 0, f"Failed to load system metadata: {e}")
    
    def _discover_existing_databases(self):
        """自动发现数据库目录中的数据库"""
        try:
            if not os.path.exists(self.data_root):
                return
            
            for item in os.listdir(self.data_root):
                item_path = os.path.join(self.data_root, item)
                
                # 跳过非目录和系统文件
                if not os.path.isdir(item_path) or item.startswith('.'):
                    continue
                
                # 检查是否是数据库目录（包含database.meta文件）
                meta_file = os.path.join(item_path, 'database.meta')
                if os.path.exists(meta_file):
                    try:
                        # 读取数据库元数据
                        with open(meta_file, 'r', encoding='utf-8') as f:
                            db_metadata = json.load(f)
                        
                        if 'database_info' in db_metadata:
                            db_name = db_metadata['database_info']['name']
                            
                            # 如果数据库还没有加载，创建数据库实例
                            if db_name not in self.databases:
                                charset = db_metadata['database_info'].get('charset', 'utf8')
                                
                                # 创建数据库实例
                                db_instance = DatabaseInstance(
                                    db_name=db_name,
                                    db_path=item_path,
                                    cache_size=self.default_cache_size,
                                    cache_policy=self.default_cache_policy,
                                    enable_locking=self.enable_locking
                                )
                                
                                self.databases[db_name] = db_instance
                                self.logger.info("DISCOVER_DB", 0, f"Auto-discovered database: {db_name}")
                                
                    except Exception as e:
                        self.logger.error("DISCOVER_DB", 0, f"Failed to discover database {item}: {e}")
                        
        except Exception as e:
            self.logger.error("DISCOVER_DB", 0, f"Failed to discover databases: {e}")
    
    def _save_system_metadata(self):
        """保存系统元数据"""
        try:
            metadata = {
                'version': '1.0',
                'created_time': datetime.now().isoformat(),
                'last_updated': datetime.now().isoformat(),
                'data_root': self.data_root,
                'databases': {
                    name: db.get_database_info().to_dict() 
                    for name, db in self.databases.items()
                }
            }
            
            with open(self.system_meta_file, 'w', encoding='utf-8') as f:
                json.dump(metadata, f, indent=2, ensure_ascii=False)
            
            self.logger.info("SAVE_META", 0, "Saved system metadata")
            
        except Exception as e:
            self.logger.error("SAVE_META", 0, f"Failed to save system metadata: {e}")
    
    def create_database(self, db_name: str, charset: str = "utf8", 
                       collation: str = "utf8_general_ci") -> bool:
        """
        创建数据库
        
        Args:
            db_name: 数据库名称
            charset: 字符集
            collation: 排序规则
            
        Returns:
            bool: 创建是否成功
        """
        if db_name in self.databases:
            self.logger.warn("CREATE_DB", 0, f"Database '{db_name}' already exists")
            return False
        
        # 检查数据库名称是否合法
        if not self._is_valid_database_name(db_name):
            self.logger.error("CREATE_DB", 0, f"Invalid database name: '{db_name}'")
            return False
        
        try:
            # 创建数据库目录
            db_path = os.path.join(self.data_root, db_name)
            os.makedirs(db_path, exist_ok=True)
            
            # 创建数据库实例
            db_instance = DatabaseInstance(
                db_name=db_name,
                db_path=db_path,
                cache_size=self.default_cache_size,
                cache_policy=self.default_cache_policy,
                enable_locking=self.enable_locking
            )
            
            # 设置数据库信息
            db_instance.db_info.charset = charset
            db_instance.db_info.collation = collation
            
            # 注册数据库实例
            self.databases[db_name] = db_instance
            
            # 保存数据库元数据文件（database.meta）
            db_instance._save_database_metadata()
            
            # 保存系统元数据
            self._save_system_metadata()
            
            self.logger.info("CREATE_DB", 0, f"Created database '{db_name}'")
            return True
            
        except Exception as e:
            self.logger.error("CREATE_DB", 0, f"Failed to create database '{db_name}': {e}")
            return False
    
    def drop_database(self, db_name: str, force: bool = False) -> bool:
        """
        删除数据库
        
        Args:
            db_name: 数据库名称
            force: 是否强制删除
            
        Returns:
            bool: 删除是否成功
        """
        if db_name not in self.databases:
            self.logger.warn("DROP_DB", 0, f"Database '{db_name}' does not exist")
            return False
        
        try:
            # 获取数据库实例
            db_instance = self.databases[db_name]
            
            # 检查是否有表（如果不是强制删除）
            tables = db_instance.list_tables()
            if not force and len(tables) > 0:
                self.logger.error("DROP_DB", 0, f"Database '{db_name}' is not empty. Use force=True to delete.")
                return False
            
            # 关闭数据库实例
            db_instance.close()
            
            # 从管理器中移除
            del self.databases[db_name]
            
            # 删除数据库目录
            # 如果强制删除，或者数据库为空，都应该删除目录
            db_path = os.path.join(self.data_root, db_name)
            if os.path.exists(db_path):
                if force or len(tables) == 0:
                    shutil.rmtree(db_path)
                    self.logger.info("DROP_DB", 0, f"Deleted database directory: {db_path}")
                else:
                    self.logger.warning("DROP_DB", 0, f"Database directory '{db_path}' not deleted (contains tables)")
            
            # 保存系统元数据
            self._save_system_metadata()
            
            self.logger.info("DROP_DB", 0, f"Dropped database '{db_name}'")
            return True
            
        except Exception as e:
            self.logger.error("DROP_DB", 0, f"Failed to drop database '{db_name}': {e}")
            return False
    
    def get_database(self, db_name: str) -> Optional[DatabaseInstance]:
        """
        获取数据库实例
        
        Args:
            db_name: 数据库名称
            
        Returns:
            Optional[DatabaseInstance]: 数据库实例，如果不存在返回None
        """
        if db_name not in self.databases:
            # 尝试延迟加载
            if self._load_database_instance(db_name):
                return self.databases.get(db_name)
            return None
        
        return self.databases[db_name]
    
    def _load_database_instance(self, db_name: str) -> bool:
        """延迟加载数据库实例"""
        try:
            db_path = os.path.join(self.data_root, db_name)
            if os.path.exists(db_path):
                db_instance = DatabaseInstance(
                    db_name=db_name,
                    db_path=db_path,
                    cache_size=self.default_cache_size,
                    cache_policy=self.default_cache_policy,
                    enable_locking=self.enable_locking
                )
                self.databases[db_name] = db_instance
                self.logger.info("LOAD_DB", 0, f"Loaded database instance: {db_name}")
                return True
        except Exception as e:
            self.logger.error("LOAD_DB", 0, f"Failed to load database instance {db_name}: {e}")
        
        return False
    
    def list_databases(self) -> List[str]:
        """获取所有数据库名称列表"""
        # 扫描数据根目录，查找所有数据库
        db_list = set(self.databases.keys())
        
        try:
            if os.path.exists(self.data_root):
                for item in os.listdir(self.data_root):
                    item_path = os.path.join(self.data_root, item)
                    if os.path.isdir(item_path) and self._is_valid_database_name(item):
                        # 检查是否是数据库目录（包含database.meta文件）
                        meta_file = os.path.join(item_path, "database.meta")
                        if os.path.exists(meta_file):
                            db_list.add(item)
        except Exception as e:
            self.logger.error("LIST_DB", 0, f"Error scanning database directories: {e}")
        
        return sorted(list(db_list))
    
    def database_exists(self, db_name: str) -> bool:
        """检查数据库是否存在"""
        return db_name in self.list_databases()
    
    def get_system_stats(self) -> Dict[str, Any]:
        """获取系统统计信息"""
        db_list = self.list_databases()
        loaded_dbs = list(self.databases.keys())
        
        stats = {
            'total_databases': len(db_list),
            'loaded_databases': len(loaded_dbs),
            'database_list': db_list,
            'loaded_database_list': loaded_dbs,
            'data_root': self.data_root,
            'system_uptime': datetime.now().isoformat()
        }
        
        # 获取已加载数据库的详细统计
        database_stats = {}
        for db_name, db_instance in self.databases.items():
            try:
                database_stats[db_name] = db_instance.get_database_stats()
            except Exception as e:
                self.logger.error("STATS", 0, f"Error getting stats for database {db_name}: {e}")
        
        stats['database_details'] = database_stats
        
        return stats
    
    def _is_valid_database_name(self, db_name: str) -> bool:
        """检查数据库名称是否合法"""
        if not db_name or len(db_name) == 0:
            return False
        
        # 不能包含特殊字符
        invalid_chars = ['/', '\\', ':', '*', '?', '"', '<', '>', '|', ' ']
        for char in invalid_chars:
            if char in db_name:
                return False
        
        # 不能是系统保留名称（但允许system数据库用于用户权限管理）
        reserved_names = ['temp', 'log', 'meta']
        if db_name.lower() in reserved_names:
            return False
        
        return True
    
    def close_all(self):
        """关闭所有数据库实例"""
        for db_name, db_instance in list(self.databases.items()):
            try:
                db_instance.close()
                self.logger.info("CLOSE_ALL", 0, f"Closed database: {db_name}")
            except Exception as e:
                self.logger.error("CLOSE_ALL", 0, f"Error closing database {db_name}: {e}")
        
        self.databases.clear()
        
        # 保存系统元数据
        self._save_system_metadata()
        
        self.logger.info("CLOSE_ALL", 0, "All databases closed")
    
    def __enter__(self):
        """支持with语句"""
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        """支持with语句"""
        self.close_all()
